package analiseSintatica.Regras.Comandos;

import AnaliseLexicaFinal.EstruturaDeDados.LinkToken;

import java.util.LinkedList;

import analiseSintatica.ErroSintaticoException;
import analiseSintatica.Regras.Regra;
import analiseSintatica.Regras.Expressoes.RegraExpressao;
import analiseSintatica.estruturadados.ErroSintatico;
import analiseSintatica.estruturadados.NoArvore;

/**
 * Classe que reconhece o comando if
 * @author anderson
 * @author Elisson
 */
public class RegraIf extends Regra {

    protected static Regra instancia;


    protected String estrutura = "if '(' <expressao> ')' <comandos> [else <comandos>]";

    /**
     * Construtor privado necessario ao singleton
     */
    private RegraIf() {
    }

    /**
     * Retorna a unica instancia dessa classe.
     * @return
     */
    public static RegraIf getInstance() {
        if (instancia == null) {
            instancia = new RegraIf();
        }
        return (RegraIf) instancia;
    }
    

    public NoArvore analisar(LinkedList<LinkToken> tokens) throws ErroSintaticoException {
        ErroSintaticoException erros = new ErroSintaticoException();

        NoArvore naoterminalif = new NoArvore("<if>", false);
        naoterminalif.adicionaFilho(reconhecerIf(tokens));
        try {
            naoterminalif.adicionaFilho(reconheceLexema(tokens, "delimitador", "(",estrutura));
        } catch (ErroSintaticoException e) {
            ErroSintatico erro = e.getErros();
            erro.setCorreto(estrutura);
            erros.addErros(erro);
            LinkedList<String> sincronizacao = RegraExpressao.getInstance().getPrimeiro();
            LinkedList<String> parentese = new LinkedList<String>();
            parentese.add("(");
            sincronizacao = getUniao(sincronizacao, parentese);
            while (!listaContem(sincronizacao, tokens.getFirst())) {
                erros.addErros("Token " + tokens.getFirst().getToken() + " nao permitido", estrutura, tokens.getFirst().getLinha());
                tokens.removeFirst();
            }
            if (tokens.getFirst().getToken().equals("delimitador") && tokens.getFirst().getLexema().equals("(")) {
                tokens.removeFirst();
            }
        }

        try {
            naoterminalif.adicionaFilho( RegraExpressao.getInstance().analisar(tokens));
        } catch (ErroSintaticoException e) {
            while (e.size() != 0) {
                erros.addErros(e.getErros());
            }
        }

        try {
            naoterminalif.adicionaFilho(reconheceLexema(tokens, "delimitador", ")",estrutura));
        } catch (ErroSintaticoException e) {
            ErroSintatico erro = e.getErros();
            erro.setCorreto(estrutura);
            erros.addErros(erro);
            LinkedList<String> sincronizacao = RegraBloco.getInstance().getPrimeiro();
            LinkedList<String> parentese = new LinkedList<String>();
            parentese.add(")");
            sincronizacao = getUniao(sincronizacao, parentese);
            while (!listaContem(sincronizacao, tokens.getFirst())) {
                erros.addErros("Token " + tokens.getFirst().getToken() + " nao permitido", estrutura, tokens.getFirst().getLinha());
                tokens.removeFirst();
            }
            if (tokens.getFirst().getToken().equals("delimitador") && tokens.getFirst().getLexema().equals(")")) {
                tokens.removeFirst();
            }
        }

        try {
            naoterminalif.adicionaFilho(RegraBloco.getInstance().analisar(tokens));
        } catch (ErroSintaticoException e) {
            while (e.size() != 0) {
                erros.addErros(e.getErros());
            }
        }

        if (tokens.getFirst().getToken().equals("else")) {
            naoterminalif.adicionaFilho(reconhecerElse(tokens));
            try {
                naoterminalif.adicionaFilho(RegraBloco.getInstance().analisar(tokens));
            } catch (ErroSintaticoException e) {
                while (e.size() != 0) {
                    erros.addErros(e.getErros());
                }
            }

        }

        if (erros.size() != 0) {
            throw erros;
        }

        return naoterminalif;
    }

    /**
     * Reconhece terminal "if"
     * @param tokens - Tokens do codigo
     * @return - Sub-arvore sintatica
     */
    public NoArvore reconhecerIf(LinkedList<LinkToken> tokens) {
        tokens.removeFirst();
        return new NoArvore("if", true);
    }

    /**
     * Reconhece terminal "else"
     * @param listaTokens - Tokens do codigo
     * @return - Sub-arvore sintatica
     */
    public NoArvore reconhecerElse(LinkedList<LinkToken> tokens) {
        tokens.removeFirst();
        return new NoArvore("else", true);
    }

    protected void setPrimeiro() {
    	this.primeiro.add("if");
    }

    protected void setSeguinte() {
        this.seguinte = RegraCmd.getInstance().getSeguinte();
    }
}
